﻿using System.Collections.Generic;
using UnityEngine;
using System;

namespace FSMStateMachine
{
    public class StateMachine : State
    {
        #region Constructor

        public StateMachine(string stateName) : base(stateName)
        {
            allStates = new List<State>();
            allParamters = new Dictionary<string, object>();
            //绑定状态机更新时调用时间
            OnStateUpdate += CheckCurrentStateTransition_Update;
        }

        public StateMachine(string stateName, string stateTag) : base(stateName, stateTag)
        {
            allStates = new List<State>();
            allParamters = new Dictionary<string, object>();
            //绑定状态机更新时调用时间
            OnStateUpdate += CheckCurrentStateTransition_Update;
        }

        #endregion

        #region StateMachine Field

        /// <summary>
        /// 所有的子状态
        /// </summary>
        private List<State> allStates;
        /// <summary>
        /// 所有的状态参数
        /// </summary>
        private Dictionary<string, object> allParamters;
        /// <summary>
        /// 当前状态
        /// </summary>
        private State currentState;
        /// <summary>
        /// 默认状态
        /// </summary>
        private State defaultState;

        #endregion

        #region About State Manager Functions

        /// <summary>
        /// 添加状态
        /// </summary>
        /// <param name="state">State.</param>
        public void AddState(State state)
        {
            if (allStates.Contains(state))
            {
                Debug.LogWarning("已包含此状态");
                return;
            }

            if(CheckStateNameContain(state.StateName))
            {
                Debug.LogWarning("状态重名，请检查状态是否有误！");
                return;
            }

            //添加状态
            allStates.Add(state);

            if(allStates.Count == 1)
            {
                //将此状态设置为默认状态
                SetDefaultState(state);
            }
        }

        /// <summary>
        /// 添加状态
        /// </summary>
        /// <param name="stateName">State name.</param>
        public void AddState(string stateName)
        {
            //通过状态名称，新建状态
            State temp = new State(stateName);
            //通过状态进行添加
            AddState(temp);
        }

        public void RemoveState(string stateName)
        {
            if(!CheckStateNameContain(stateName))
            {
                Debug.LogWarning("该状态不属于此状态机管理，无法移除！");
                return;
            }

            //如果要移除当前状态
            if(currentState.StateName == stateName)
            {
                Debug.LogWarning("该状态正在执行，无法移除！");
                return;
            }
            //移除状态
            allStates.Remove(FindStateByName(stateName));
            //如果当前状态是默认状态
            if (defaultState.StateName == stateName)
            {
                //设置新的默认状态
                SetNewDefaultState();
            }
        }

        #region Obsolete Functions

        /// <summary>
        /// 切换状态
        /// </summary>
        /// <param name="stateName">State name.</param>
        [Obsolete("", true)]
        private void TransitionState(string stateName)
        { 
            //检测状态是否归当前状态机管理
            if(!CheckStateNameContain(stateName))
            {
                return;
            }
            //如果当前状态不为空
            if (currentState != null)
            {
                //如果当前状态是状态机
                if (currentState is StateMachine)
                {
                    ((StateMachine)currentState).StopMachine();
                }
                else
                {
                    //移除Update
                    if (currentState.OnStateUpdate != null)
                        //上一个状态的Update取消
#pragma warning disable RECS0020 // 委托减法具有不可预测的结果
                        UnityMonoStateHelper.instance.runStateUpdate -= currentState.OnStateUpdate;
#pragma warning restore RECS0020 // 委托减法具有不可预测的结果
                    if (currentState.OnStateExit != null)
                        //上一个状态执行离开
                        currentState.OnStateExit(currentState);
                }
            }
            //获取新状态
            State newState = FindStateByName(stateName);
            if (newState == null)
                return;
            //设置新的状态
            currentState = newState;
            //如果当前状态是状态机
            if (currentState is StateMachine)
            {
                StateMachine machine = currentState as StateMachine;
                machine.StartMachine();
            }
            else
            {
                //执行NewState的进入状态事件
                if (currentState.OnStateEnter != null)
                    //当前状态执行进入
                    currentState.OnStateEnter(currentState);
                if (currentState.OnStateUpdate != null)
                {
                    //当前状态执行Update
                    UnityMonoStateHelper.instance.runStateUpdate += currentState.OnStateUpdate;
                    UnityMonoStateHelper.instance.runStateParamter = currentState;
                }
            }
        }
        #endregion

        #region Replace Functions

        private void TransitionNewState(string stateName)
        {
            //检测状态是否归当前状态机管理
            if (!CheckStateNameContain(stateName))
            {
                return;
            }
            //如果当前状态不为空
            if (currentState != null)
            {
                //如果当前状态是状态机
                if (currentState is StateMachine)
                {
                    ((StateMachine)currentState).StopCurrentMachine();
                }
                else
                {
                    //离开上一个状态
                    currentState.CurrentStateExit();
                }
            }
            //获取新状态
            State newState = FindStateByName(stateName);

            if (newState == null)
                return;
            //设置新的状态
            currentState = newState;
            //如果当前状态是状态机
            if (currentState is StateMachine)
            {
                StateMachine machine = currentState as StateMachine;
                machine.StartCurrentMachine();
            }
            else
            {
                //进入当前状态
                currentState.CurrentStateEnter();
            }
        }

        #endregion

        #endregion

        #region State Manager Utility Functions

        #region Obsolete Function

        /// <summary>
        /// 启动状态机
        /// </summary>
        [Obsolete("", true)]
        public void StartMachine()
        { 
            //执行进入
            if(OnStateEnter!=null)
            {
                OnStateEnter(this);
            }
            //绑定更新
            if(OnStateUpdate!=null)
            {
                UnityMonoStateHelper.instance.runStateUpdate
                    += OnStateUpdate;
            }

            //启动子状态
            if(currentState !=null)
            {
                //如果当前状态是状态机
                if (currentState is StateMachine)
                {
                    ((StateMachine)currentState).StartMachine();
                    return;
                }

                //执行进入
                if (currentState.OnStateEnter != null)
                {
                    currentState.OnStateEnter(currentState);
                }
                //绑定更新
                if (currentState.OnStateUpdate != null)
                {
                    UnityMonoStateHelper.instance.runStateUpdate
                        += currentState.OnStateUpdate;
                }
            }
        }

        /// <summary>
        /// 停止状态机
        /// </summary>
        [Obsolete("", true)]
        public void StopMachine()
        {
            //启动子状态
            if (currentState != null)
            {
                //如果当前状态是状态机
                if (currentState is StateMachine)
                {
                    ((StateMachine)currentState).StopMachine();
                }
                else
                {
                    //绑定更新
                    if (currentState.OnStateUpdate != null)
                    {
#pragma warning disable RECS0020 // 委托减法具有不可预测的结果
                        UnityMonoStateHelper.instance.runStateUpdate
                            -= currentState.OnStateUpdate;
#pragma warning restore RECS0020 // 委托减法具有不可预测的结果
                    }

                    //执行进入
                    if (currentState.OnStateExit != null)
                    {
                        currentState.OnStateExit(currentState);
                    }
                }
            }
            //绑定更新
            if (OnStateUpdate != null)
            {
#pragma warning disable RECS0020 // 委托减法具有不可预测的结果
                UnityMonoStateHelper.instance.runStateUpdate
                    -= OnStateUpdate;
#pragma warning restore RECS0020 // 委托减法具有不可预测的结果
            }
            //执行进入
            if (OnStateExit != null)
            {
                OnStateExit(this);
            }
        }

        #endregion

        #region Replace Function

        /// <summary>
        /// 启动当前状态机
        /// </summary>
        public void StartCurrentMachine()
        {
            //进入当前状态机
            CurrentStateEnter();

            //启动子状态
            if (currentState != null)
            {
                //如果当前状态是状态机
                if (currentState is StateMachine)
                {
                    ((StateMachine)currentState).StartCurrentMachine();
                    return;
                }

                //否则，进入子状态
                currentState.CurrentStateEnter();
            }
        }

        /// <summary>
        /// 停止当前状态机
        /// </summary>
        public void StopCurrentMachine()
        {
            //启动子状态
            if (currentState != null)
            {
                //如果当前状态是状态机
                if (currentState is StateMachine)
                {
                    //递归离开子状态
                    ((StateMachine)currentState).StopCurrentMachine();
                    //离开当前子状态机
                    //CurrentStateExit();
                }
                else
                {
                    //离开子状态
                    currentState.CurrentStateExit();
                }
            }
            //离开当前子状态机
            CurrentStateExit();
        }

        #endregion

        /// <summary>
        /// 检测状态名是否与当前管理器的子状态重名
        /// </summary>
        /// <returns><c>true</c>, if state name contain was checked, <c>false</c> otherwise.</returns>
        /// <param name="stateName">State name.</param>
        private bool CheckStateNameContain(string stateName)
        {
            foreach (var item in allStates)
            {
                if (item.StateName == stateName)
                    return true;
            }

            return false;
        }
        /// <summary>
        /// 设置默认状态
        /// </summary>
        /// <param name="state">State.</param>
        private void SetDefaultState(State state)
        {
            defaultState = state;
            //如果当前状态为空
            if(currentState == null)
            {
                //设置当前状态为默认状态
                currentState = defaultState;
            }
        }
        /// <summary>
        /// 设置新的默认状态
        /// </summary>
        private void SetNewDefaultState()
        {
            if (allStates.Count == 0)
                return;
            SetDefaultState(allStates[0]);
        }

        /// <summary>
        /// 通过名称找一个状态
        /// </summary>
        /// <returns>The state by name.</returns>
        /// <param name="stateName">State name.</param>
        private State FindStateByName(string stateName)
        {
            foreach (var item in allStates)
            {
                if (item.StateName == stateName)
                    return item;
            }

            return null;
        }

        #endregion

        #region State Manager Event Binding

        private void CheckCurrentStateTransition_Update(State state)
        {
            if (currentState == null)
                return;
            foreach (var item in currentState.GetAllStateTransition())
            {
                //执行条件方法
                if(item.Value())
                {
                    //返回true，说明条件满足了
                    //切换状态(过时)
                    //TransitionState(item.Key);
                    //新切换状态
                    TransitionNewState(item.Key);
                    return;
                }
            }
        }

        #endregion

        #region State Manager Parameters Functions

        /// <summary>
        /// 设置参数
        /// </summary>
        /// <param name="paraName">Para name.</param>
        /// <param name="paraValue">Para value.</param>
        public void SetParamter(string paraName, object paraValue)
        {
            if (allParamters.ContainsKey(paraName))
            {
                allParamters[paraName] = paraValue;
            }
            else
            {
                allParamters.Add(paraName, paraValue);
            }
        }

        /// <summary>
        /// 获取参数
        /// </summary>
        /// <returns>The paramter.</returns>
        /// <param name="paraName">Para name.</param>
        public object GetParamter(string paraName)
        {
            if (allParamters.ContainsKey(paraName))
            {
                return allParamters[paraName];
            }
            return null;
        }

        #endregion
    }
}